﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Linq;
using System.Windows;

namespace OTDR_OPT
{

    /* 产品波长添加、删除、读取配置 
     线性点设置、修改
     回看点设置、修改、删除
         */
    public class ProductManagement
    {
        private static ProductManagement pwm = null;

        public event EventHandler<ProductListChangedArgs> ProductNameListChanged;

        //配置文件保存的完整名称
        private string FileName = System.Environment.CurrentDirectory + "\\" + "Product.xml";


        //单例模式，将构造器设为私有
        private ProductManagement() { }


        //获取对象
        public static ProductManagement GetInstance()
        {
            if (pwm == null){
                pwm = new ProductManagement();
            }
            return pwm;
        }

        
        //添加波长
        private void AddWavelength(string productName,string wavelength)
        {
            if (!File.Exists(FileName))
            {
                return;
            }
            XElement root = XElement.Load(FileName);
            #region 查找对应机型的节点
            var result = (from elem in root.Elements("Product")
                          where elem.Attribute("ProductName") != null
                          && elem.Attribute("ProductName").Value.Equals(productName)
                          select elem
                          );
            if (result.Count() == 0) { return; }
            #endregion
            XElement productElement = result.SingleOrDefault();
            XElement wavelengthElement = new XElement("Wavelength",new XAttribute("Wavelength",wavelength));
            var wavelengthResult = (from elem in productElement.Elements("Wavelength")
                                    where elem.Attribute("Wavelength") != null
                                    select elem);
            #region 如果不存在任何波长，则直接写入一个波长
            if (wavelengthResult.Count() == 0) {
                productElement.Add(wavelengthElement);
                root.Save(FileName);
                return;
            }
            #endregion
            #region 如果波长列表非空，则在比当前波长值大的波长前面插入当前波长
            foreach (XElement element in wavelengthResult)
            {
                int currentWavelength = Convert.ToInt16(element.Attribute("Wavelength").Value);
                int paramWavelength = Convert.ToInt16(wavelength);
                if(currentWavelength > paramWavelength)
                {
                    XElement xElement = element;
                    xElement.AddBeforeSelf(new XElement("Wavelength",new XAttribute("Wavelength",wavelength)));
                    root.Save(FileName);
                    return;
                }
            }
            #region 如果没有比当前波长大的波长，则将当前波长写在最后一个波长后面
            XElement lastElement = wavelengthResult.Last();
            lastElement.AddAfterSelf(new XElement("Wavelength", new XAttribute("Wavelength", wavelength)));
            root.Save(FileName);
            #endregion
            #endregion
        }


        //删除波长
        private void DeleteWavelength(string productName, string wavelength)
        {
            if (!File.Exists(FileName))
            {
                return;
            }
            XElement root = XElement.Load(FileName);
            var result = (from elem in root.Elements("Product")
                          where elem.Attribute("ProductName") != null
                          && elem.Attribute("ProductName").Value.Equals(productName)
                          select elem
                          );
            if (result.Count() == 0) { return; }
            XElement productElement = result.SingleOrDefault();
            var waveResult = (from elem in productElement.Elements("Wavelength")
                              where elem.Attribute("Wavelength") != null
                              && elem.Attribute("Wavelength").Value.Equals(wavelength)
                              select elem
                              );
            if (waveResult.Count() == 0) { return; }
            XElement waveElement = waveResult.SingleOrDefault();
            waveElement.Remove();
            root.Save(FileName);
        }


        //添加线性点
        private void AddLinear(string productName,Linear linear) {
            if (!File.Exists(FileName))
            {
                return;
            }
            XElement root = XElement.Load(FileName);
            #region 查找对应机型的节点
            var result = (from elem in root.Elements("Product")
                          where elem.Attribute("ProductName") != null
                          && elem.Attribute("ProductName").Value.Equals(productName)
                          select elem
                          );
            if (result.Count() == 0) { return; }
            int index = linear.Index;
            XElement linearElement = new XElement("Linear", new XAttribute("Index", index),
                new XElement("P1", linear.P1), new XElement("P2", linear.P2));  //线性点
            XElement productElement = result.SingleOrDefault();
            #endregion
            var linearResult = (from elem in productElement.Elements("Linear")
                                where elem.Attribute("Index") != null
                                select elem);
            #region 如果不存在任何Linear节点，则直接写入节点
            if (linearResult.Count() == 0) {
                productElement.Add(linearElement);
                root.Save(FileName);
                return;
            }
            #endregion

            #region 对比当前值的Index与传入的Index的大小，如果匹配，则修改该节点。如果当前的值大于传入值，则在当前位置前面插入节点
            List<XElement> linearList = linearResult.ToList();
            for (int i = 0; i < linearList.Count(); i++)
            {
                int currentIndex = Convert.ToInt16(linearList[i].Attribute("Index").Value.ToString());
                #region 如果有对应的线性点，则刷新线性点的值
                if (currentIndex == index)
                {
                    XElement xElement = linearList[i];
                    var p1Result = (from elem in xElement.Elements("P1")
                                    select elem
                                    ).SingleOrDefault();
                    p1Result.Value = linear.P1.ToString();

                    var p2Result = (from elem in xElement.Elements("P2")
                                    select elem
                        ).SingleOrDefault();
                    p2Result.Value = linear.P2.ToString();
                    root.Save(FileName);
                    return;
                }
                #endregion

                #region 如果索引号大于传入值，则在当前位置前插入一个节点信息
                if (currentIndex > index)
                {
                    XElement xElement = linearList[i];
                    xElement.AddBeforeSelf(linearElement);
                    root.Save(FileName);
                    return;
                }
                #endregion
            }
            XElement endElement = linearList[linearList.Count - 1];
            endElement.AddAfterSelf(linearElement);
            root.Save(FileName);
            #endregion
        }


        //删除线性点
        private void DeleteLinear(string productName,List<Linear> linears) {
            if (!File.Exists(FileName))
            {
                return;
            }
            XElement root = XElement.Load(FileName);
            var result = (from element in root.Elements("Product")
                          where element.Attribute("ProductName") != null
                          && element.Attribute("ProductName").Value.Equals(productName)
                          select element
                          );
            if (result.Count() == 0)
            {
                return;
            }
            XElement productElement = result.SingleOrDefault();
            List<Linear> localLinears = GetLinearList(productName); //本地线性点
            Dictionary<int, Linear> linearDic = new Dictionary<int, Linear>();
            foreach(Linear linear in linears)
            {
                int index = linear.Index;
                linearDic.Add(index, linear);
            }
            foreach(Linear localLinear in localLinears)
            {
                int localIndex = localLinear.Index;
                if (!linearDic.Keys.Contains(localIndex))
                {
                    XElement linearXElement = (from elem in productElement.Elements("Linear")
                                        where elem.Attribute("Index") != null
                                        && elem.Attribute("Index").Value.Equals(localIndex.ToString())
                                        select elem
                                      ).SingleOrDefault();
                    linearXElement.Remove();
                }
            }
            root.Save(FileName);
        }


        //保存复测点
        public void SaveCheckPoint(string productName,Dictionary<string,List<CheckPoint>> checkPointDic) {
            if (!File.Exists(FileName))
            {
                return;
            }
            XElement root = XElement.Load(FileName);
            var result = (from element in root.Elements("Product")
                          where element.Attribute("ProductName") != null
                          && element.Attribute("ProductName").Value.Equals(productName)
                          select element
              );
            //配置文件中，应有且只有一个该机型的配置清单
            if (result.Count() != 1)
            {
                return;
            }
            XElement productElement = result.SingleOrDefault();
            string[] wavlengthArr = checkPointDic.Keys.ToArray();
            #region 遍历每一个波长，将复查点写入配置文件
            foreach (string wavlength in wavlengthArr)
            {
                 var wavelengthResult = (from element in productElement.Elements("Wavelength")
                                              where element.Attribute("Wavelength") != null
                                              && element.Attribute("Wavelength").Value.Equals(wavlength)
                                              select element
                                              );
                if(wavelengthResult.Count() != 1)
                {
                    continue;
                }
                XElement wavelengthElement = wavelengthResult.SingleOrDefault();
                wavelengthElement.RemoveNodes(); //清除原节点数据
                #region 将传入的复查点写入波长对应的节点
                List<CheckPoint> checkPointList = checkPointDic[wavlength];
                foreach(CheckPoint check in checkPointList)
                {
                    XElement checkElement = new XElement("Check",new XAttribute("Power",check.CheckPower),new XElement("Limit",check.Limit));
                    wavelengthElement.Add(checkElement);
                }
                #endregion
            }
            root.Save(FileName);
            #endregion
        }


        //保存数据
        public void SaveData(Product product)
        {
            #region 如果文件不存在，添加文件
            if (!File.Exists(FileName))
            {
                XDocument xDoc = new XDocument(
                    new XDeclaration("1.0", "utf-8", "yes"),
                    new XElement("Config"));
                xDoc.Save(FileName);
            }
            #endregion

            XElement root = XElement.Load(FileName);
            var result = (from element in root.Elements("Product")
                          where element.Attribute("ProductName") != null
                          && element.Attribute("ProductName").Value.Equals(product.ProductName)
                          select element
                          );

            #region 如果配置文件中不存在该机型名称，则直接将该机型名称、波长列表、线性点添加到配置文件
            if (result.Count() == 0)
            {
                XElement productElement = new XElement("Product",
                    new XAttribute("ProductName", product.ProductName));
                //遍历波长列表，添加到配置文件
                foreach (string wavelength in product.Wavelengthes)
                {
                    XElement wavelengthElement = new XElement("Wavelength",
                        new XAttribute("Wavelength", wavelength));
                    productElement.Add(wavelengthElement);
                }
                //遍历线性点列表，添加到配置文件
                foreach(Linear linear in product.Linears)
                {
                    string index = linear.Index.ToString();
                    string p1 = linear.P1.ToString();
                    string p2 = linear.P2.ToString();
                    XElement linearElement = new XElement("Linear",
                        new XAttribute("Index",index),new XElement("P1",p1),new XElement("P2",p2));
                    productElement.Add(linearElement);
                }
                root.Add(productElement);
                ProductListChanged(product.ProductName,"Add");
                root.Save(FileName);
                return;
            }
            #endregion

            #region 如果配置文件中存在该机型名称，则对比配置文件中的波长列表与传入的波长列表、线性点差异部分修改
            bool isChanged = false;
            try
            {
                XElement productElement = result.Single();
                #region 遍历传入的波长列表，如果配置文件中不存在，则添加该波长
                foreach (string wavelength in product.Wavelengthes)
                {
                    var wavelengthResult = (from waveElement in productElement.Elements("Wavelength")
                                            where waveElement.Attribute("Wavelength") != null
                                            && waveElement.Attribute("Wavelength").Value.Equals(wavelength)
                                            select waveElement
                                            );
                    if (wavelengthResult.Count() == 0)
                    {
                        AddWavelength(product.ProductName,wavelength);
                    }
                }
                #endregion

                #region 如果配置文件中存在该波长，但该波长未选中，则将配置文件中的波长去除
                List<string> wavelengthList = GetWaveList(product.ProductName);
                foreach (string wavlength in wavelengthList)
                {
                    if (!product.Wavelengthes.Contains(wavlength))
                    {
                        DeleteWavelength(product.ProductName, wavlength);
                    }
                }
                #endregion

                #region 添加线性点
                List<Linear> linearList = product.Linears;
                foreach(Linear linear in linearList)
                {
                    AddLinear(product.ProductName, linear);
                }
                #endregion

                #region 将配置文件中存在，本次传入中不存在的线性点删除
                if (linearList.Count < GetLinearList(product.ProductName).Count)
                {
                    DeleteLinear(product.ProductName, product.Linears);
                }
                #endregion

                if (isChanged)
                {
                    root.Save(FileName);
                }
            }catch(Exception e) { throw e; }
            #endregion
        }


        //删除机型
        public void DeleteProduct(string productName)
        {
            if (!File.Exists(FileName))
            {
                return;
            }
            XElement root = XElement.Load(FileName);
            var result = (from elem in root.Elements("Product")
                          where elem.Attribute("ProductName") != null
                          && elem.Attribute("ProductName").Value.Equals(productName)
                          select elem
                          );
            if (result.Count() == 0)
            {
                return;
            }
            IEnumerator<XElement> enumerator = result.GetEnumerator();
            while (enumerator.MoveNext())
            {
                enumerator.Current.Remove();
            }
            ProductListChanged(productName,"Remove");
            root.Save(FileName);
        }


        //获取机型的复查点
        public Dictionary<string,List<CheckPoint>> GetCheckPointDic(string productname) {
            if (!File.Exists(FileName))
            {
                return null;
            }
            XElement root = XElement.Load(FileName);
            var productResult = (from element in root.Elements("Product")
                                 where element.Attribute("ProductName") != null
                                 && element.Attribute("ProductName").Value.Equals(productname)
                                 select element
                                 );
            if (productResult.Count() == 0)
            {
                return null;
            }
            XElement productElement = productResult.SingleOrDefault();
            var waveResult = (from elem in productElement.Elements("Wavelength")
                              select elem);
            if (waveResult.Count() == 0)
            {
                return null;
            }
            //遍历每个波长，读取对应的复测点
            Dictionary<string, List<CheckPoint>> checkPointDic = new Dictionary<string, List<CheckPoint>>();
            foreach (object waveObj in waveResult) {
                XElement waveElement = (XElement)waveObj;
                string wavelength = waveElement.Attribute("Wavelength").Value.Trim(); //波长
                var checkPointsResult = (from elem in waveElement.Elements("Check")
                                         select elem
                                         );
                if (checkPointsResult.Count() == 0)
                {
                    continue;
                }
                List<CheckPoint> checkPointList = new List<CheckPoint>();
                foreach(object checkObj in checkPointsResult) //遍历复查点，添加到清单
                {
                    XElement checkElement = (XElement)checkObj;
                    string power = checkElement.Attribute("Power").Value.Trim();
                    XElement limitElement = (from ele in checkElement.Elements("Limit")
                                       select ele).SingleOrDefault();
                    string limit = limitElement.Value.Trim();
                    CheckPoint check = new CheckPoint();
                    check.CheckPower = Convert.ToDouble(power);
                    check.Limit = Convert.ToDouble(limit);
                    checkPointList.Add(check);
                }
                checkPointDic.Add(wavelength,checkPointList);
            }
            return checkPointDic;
        }


        //获取机型的线性清单
        public List<Linear> GetLinearList(string productName) {
            if (!File.Exists(FileName))
            {
                return null;
            }
            XElement root = XElement.Load(FileName);
            var result = (from element in root.Elements("Product")
                          where element.Attribute("ProductName") != null
                          && element.Attribute("ProductName").Value.Equals(productName)
                          select element
                          );
            if (result.Count() == 0)
            {
                return null;
            }
            try {
                List<Linear> linearList = new List<Linear>();
                XElement productElement = result.SingleOrDefault();
                var linearResult = (from element in productElement.Elements("Linear")
                                    select element);
                if (linearResult.Count() == 0)
                {
                    return null;
                }
                #region 遍历线性点，将内容添加到配置文件
                foreach(XElement elem in linearResult)
                {
                    int index = Convert.ToInt16(elem.Attribute("Index").Value.ToString());
                    double p1 = Convert.ToDouble(elem.Element("P1").Value.ToString());
                    double p2 = Convert.ToDouble(elem.Element("P2").Value.ToString());
                    Linear linear = new Linear();
                    linear.Index = index;
                    linear.P1 = p1;
                    linear.P2 = p2;
                    linearList.Add(linear);
                }
                #endregion
                return linearList;
            } catch(Exception e) { throw e; }
        }


        //获取机型的波长列表
        public List<string> GetWaveList(string productName)
        {
            //文件不存在，直接返回null
            if (!File.Exists(FileName))
            {
                return null;
            }
            XElement root = XElement.Load(FileName);
            var result = (from element in root.Elements("Product")
                          where element.Attribute("ProductName") != null
                          && element.Attribute("ProductName").Value.Equals(productName)
                          select element
                          );
            if (result.Count() == 0)
            {
                return null;
            }
            try
            {
                List<string> wavelengthList = new List<string>();
                var wavelengthes = (from element in result.Single().Descendants("Wavelength")
                                    where element.Attribute("Wavelength") != null
                                    select element.Attribute("Wavelength"));
                int count = wavelengthes.Count();
                IEnumerator<XAttribute> enumerator = wavelengthes.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    wavelengthList.Add(enumerator.Current?.Value);
                }
                return wavelengthList;
            }
            catch (Exception e) { throw e; }
        }


        //获取机型清单
        public List<string> GetProductList()
        {
            if (!File.Exists(FileName))
            {
                return null;
            }
            XElement root = XElement.Load(FileName);
            var result = (from elem in root.Elements("Product")
                          where elem.Attribute("ProductName") != null
                          select elem.Attribute("ProductName"));
            if (result.Count() == 0)
            {
                return null;
            }
            List<string> productNameList = new List<string>();
            IEnumerator<XAttribute> enumerator = result.GetEnumerator();
            while (enumerator.MoveNext())
            {
                productNameList.Add(enumerator.Current?.Value);
            }
            return productNameList;
        }


        ////机型名称节点发生变化时，产生一个事件，由订阅者使用
        private void ProductListChanged(string productname,string changeType)
        {
            ProductListChangedArgs changedArgs = new ProductListChangedArgs();
            changedArgs.Productname = productname;
            changedArgs.ChangeType = changeType;
            ProductNameListChanged?.Invoke(this, changedArgs);
        }

    }
}
